package com.newtouch.cq.base.starter.business.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.newtouch.cq.base.starter.business.entity.SysOrganization;
import com.newtouch.cq.base.starter.business.entity.SysRole;
import com.newtouch.cq.base.starter.business.entity.SysUser;
import com.newtouch.cq.base.starter.business.entity.SysUserRole;
import com.newtouch.cq.base.starter.business.mapper.BaseSysUserMapper;
import com.newtouch.cq.base.starter.business.model.UserDetailsImpl;
import com.newtouch.cq.base.starter.business.model.dto.*;
import com.newtouch.cq.base.starter.business.model.dto.*;
import com.newtouch.cq.base.starter.business.model.vo.SysUserPageVo;
import com.newtouch.cq.base.starter.business.model.vo.SysUserVo;
import com.newtouch.cq.base.starter.business.model.vo.UserVO;
import com.newtouch.cq.base.starter.business.service.IBaseSysOrganizationService;
import com.newtouch.cq.base.starter.business.service.IBaseSysRoleService;
import com.newtouch.cq.base.starter.business.service.IBaseSysUserRoleService;
import com.newtouch.cq.base.starter.business.service.IBaseSysUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.newtouch.cq.base.starter.lang.util.CurrentUserUtil;
import com.newtouch.cq.lang.em.BaseExceptionEnum;
import com.newtouch.cq.lang.em.StatusEnum;
import com.newtouch.cq.lang.exception.MccBizException;
import com.newtouch.cq.lang.result.MccObjectResult;
import com.newtouch.cq.lang.result.MccPageResult;
import com.newtouch.cq.lang.util.DateUtils;
import com.newtouch.cq.lang.util.LogUtil;
import com.newtouch.cq.mybatis.util.DbUtil;
import com.newtouch.cq.security.exception.AuthException;
import com.newtouch.cq.security.util.PWDUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 系统用户表 服务实现类
 * </p>
 *
 * @author Alex
 * @since 2021-08-02
 */
@Service
public class BaseSysUserServiceImpl extends ServiceImpl<BaseSysUserMapper, SysUser> implements IBaseSysUserService {

    private Log log = LogFactory.get(BaseSysUserServiceImpl.class);

    @Resource
    private IBaseSysUserRoleService userRoleService;

    @Resource
    private IBaseSysRoleService roleService;

    @Resource
    private IBaseSysOrganizationService organizationService;

    private int PWD_LENGTH_DEFALT = 6;

    @Override
    @Transactional
    public void add(SysUserAddDTO userAddDTO) {
        UserDetailsImpl operator = CurrentUserUtil.userOrThrow();
        SysUser user = new SysUser();
        BeanUtil.copyProperties(userAddDTO, user, CopyOptions.create().ignoreNullValue());
        user.setPassword(PWDUtil.encryption(userAddDTO.getPassword()));
        user.setStatus(StatusEnum.VALID);
        user.setCreateId(operator.getId());
        user.setCreateTime(DateUtils.localDateTime());
        user.setUpdateId(operator.getId());
        user.setUpdateTime(user.getCreateTime());
        baseMapper.insert(user);

        SysUserRoleDTO userRole = new SysUserRoleDTO();
        userRole.setUserId(user.getId());
        userRole.setRoleIds(userAddDTO.getRoleIds());
        userRoleService.deleteByUserIdAndSave(userRole);
    }

    @Override
    @Transactional
    public void update(long id, SysUserUpdDTO dto) {
        long operatorId = CurrentUserUtil.userIdOrThrow();
        DbUtil.containId(baseMapper, id, log);
        SysUser user = new SysUser();
        BeanUtil.copyProperties(dto, user, CopyOptions.create().ignoreNullValue());
        user.setId(id);
        user.setUpdateId(operatorId);
        user.setUpdateTime(DateUtils.localDateTime());
        baseMapper.updateById(user);

        SysUserRoleDTO userRole = new SysUserRoleDTO();
        userRole.setUserId(user.getId());
        userRole.setRoleIds(dto.getRoleIds());
        userRoleService.deleteByUserIdAndSave(userRole);
    }

    @Override
    public void updateOwnInfo(SysUserOwnUpdDTO dto) {
        long operatorId = CurrentUserUtil.userIdOrThrow();
        SysUser user = new SysUser();
        BeanUtil.copyProperties(dto, user, CopyOptions.create().ignoreNullValue());
        user.setId(operatorId);
        user.setUpdateId(operatorId);
        user.setUpdateTime(DateUtils.localDateTime());
        baseMapper.updateById(user);
    }

    @Override
    public void updatePassword(SysUserPwdUpdDTO dto) {
        long operatorId = CurrentUserUtil.userIdOrThrow();
        SysUser user = baseMapper.selectById(operatorId);
        if(!PWDUtil.check(dto.getOldPassword(),user.getPassword())) {
            LogUtil.error(log,BaseExceptionEnum.ACCOUNT_PASSWORD_ERROR,"密码错误");
            throw new MccBizException(BaseExceptionEnum.ACCREDIT_INVALID_OVERDUE).setMessage("密码错误");
        }
        user.setId(operatorId);
        user.setPassword(PWDUtil.encryption(dto.getNewPassword()));
        user.setUpdateId(operatorId);
        user.setUpdateTime(DateUtils.localDateTime());
        baseMapper.updateById(user);
    }

    @Override
    public UserVO findUserVOByUsername(String username) {
        LambdaQueryWrapper<SysUser> wrapper = Wrappers.lambdaQuery(SysUser.class)
                .eq(SysUser::getUsername, username);
        List<SysUser> users = baseMapper.selectList(wrapper);

        if (CollUtil.isEmpty(users)) {
            LogUtil.error(log, BaseExceptionEnum.ACCOUNT_PASSWORD_ERROR, "账号错误");
            throw new AuthException(BaseExceptionEnum.ACCOUNT_PASSWORD_ERROR);
        }
        UserVO userVO = new UserVO();
        BeanUtil.copyProperties(users.get(0), userVO, CopyOptions.create().ignoreNullValue());
        return userVO;
    }

    @Override
    public MccPageResult<SysUserPageVo> pageList(SysUserPageDTO dto) {
        UserDetailsImpl operator = CurrentUserUtil.user();
        //登录者没有部门权限时直接返回空页面数据
        if (CollUtil.isEmpty(operator.getOrgIdList())) {
            return MccPageResult.success(dto.getCurrent(), dto.getSize());
        }
//        LambdaQueryWrapper<SysUser> wrapper = Wrappers.lambdaQuery(SysUser.class)
//                .ne(SysUser::getStatus, StatusEnum.DELETE.getValue())
//                .ne(operator.getId() != 1, SysUser::getId, 1)
//                .in(SysUser::getOrgId, operator.getOrgIdList())
//                .like(ObjectUtil.isNotNull(dto.getUsername()), SysUser::getUsername, dto.getUsername());
//        Page<SysUser> userPage = baseMapper.selectPage(dto.buildPage(), wrapper);
//        return MccPageResult.success(userPage);

        Map<String, Object> param = MapUtil.newHashMap();
        param.put("operatorId",operator.getId());
        param.put("username",dto.getUsername());
        param.put("realName",dto.getRealName());
        param.put("orgId",dto.getOrgId());
        param.put("orgIds",operator.getOrgIdList());

        return MccPageResult.success(baseMapper.pageList(dto.buildPage(),param));
    }

    @Override
    public MccPageResult<SysUser> getRoleUserPagedList(long roleId, SysUserPageDTO dto) {
        List<SysUserRole> userRoles = userRoleService.getAllByRoleId(roleId);

        if (CollUtil.isEmpty(userRoles)) {
            return MccPageResult.success(dto.getCurrent(), dto.getSize());
        }
        List<Long> userIds = CollUtil.newArrayList();
        userRoles.stream().forEach(role -> {
            userIds.add(role.getUserId());
        });

        LambdaQueryWrapper<SysUser> wrapper = Wrappers.lambdaQuery(SysUser.class)
                .ne(SysUser::getStatus, StatusEnum.DELETE.getValue())
                .eq(StrUtil.isNotEmpty(dto.getUsername()), SysUser::getUsername, dto.getUsername())
                .in(SysUser::getId, userIds);

        Page page = baseMapper.selectPage(dto.buildPage(), wrapper);

        return MccPageResult.success(page);
    }

    @Override
    public SysUserVo getInfo(long id) {
        SysUser user = getById(id);
        List<SysUserRole> userRoles = userRoleService.getAllByUserId(id);
        List<Long> roleIds = CollUtil.newArrayList();
        List<String> roleNames = CollUtil.newArrayList();
        userRoles.stream().forEach(userRole -> {
            roleIds.add(userRole.getRoleId());
            SysRole role = roleService.getById(userRole.getRoleId());
            roleNames.add(role.getRoleName());
        });

        SysOrganization org = organizationService.getById(user.getOrgId());

        SysUserVo userVo = new SysUserVo();
        BeanUtil.copyProperties(user, userVo, CopyOptions.create().ignoreNullValue());
        userVo.setRoleIds(roleIds);
        userVo.setRoleNames(CollUtil.join(roleNames,","));
        userVo.setOrgName(org.getName());
        //将密码置空
        userVo.setPassword(null);
        return userVo;
    }

    @Override
    public MccObjectResult<SysUserVo> getOwnInfo() {
        long id = CurrentUserUtil.userIdOrThrow();
        return MccObjectResult.success(getInfo(id));
    }

    @Override
    public String resetPwd(long id) {
        UserDetailsImpl operator = CurrentUserUtil.userOrThrow();
        DbUtil.containId(baseMapper, id, log);
        SysUser user = new SysUser();
        user.setId(id);

        String new_pwd = RandomUtil.randomString(PWD_LENGTH_DEFALT);

        user.setPassword(PWDUtil.encryption(new_pwd));
        user.setUpdateId(operator.getId());
        user.setUpdateTime(DateUtils.localDateTime());
        baseMapper.updateById(user);

        return new_pwd;
    }

    @Override
    public void userDel(long id) {
        long operatorId = CurrentUserUtil.userIdOrThrow();
        if (operatorId == id) {
            LogUtil.error(log, BaseExceptionEnum.FAIL, "不能删除自己");
            throw new MccBizException(BaseExceptionEnum.FAIL).setMessage("不能删除自己");
        }
        SysUser userDel = new SysUser();
        userDel.setId(id);
        userDel.setStatus(StatusEnum.DELETE);
        userDel.setUpdateId(operatorId);
        userDel.setUpdateTime(DateUtils.localDateTime());
        baseMapper.updateById(userDel);

        userRoleService.deleteByUserId(id);
    }
}
